package com.sfac.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sfac.account.User;
import com.sfac.account.UserRole;
import com.sfac.account.vo.UserVo;
import com.sfac.common.vo.Result;
import com.sfac.common.vo.Search;
import com.sfac.dao.UserDao;
import com.sfac.dao.UserRoleDao;
import com.sfac.service.TestFeignClient;
import com.sfac.service.UserService;
import com.sfac.test.City;
import com.sfac.utils.MD5Util;
import io.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Optional;

/**
 * UserServiceImpl
 */
@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;
	@Autowired
	private UserRoleDao userRoleDao;
	@Autowired
	private TestFeignClient testFeignClient;

	@Override
	@Transactional
	public Result<User> login(User user) {
		User temp = userDao.getUserByUserNameAndPassword(user.getUserName(), MD5Util.getMD5(user.getPassword()));
		if (temp == null) {
			return new Result<>(Result.ResultStatus.FAILED.code, "用户名或密码错误。");
		}
		return new Result<>(Result.ResultStatus.SUCCESS.code, "Success.", temp);
	}

	@Override
	@Transactional
	public Result<User> insertUser(User user) {
		User temp = userDao.getUserByUserName(user.getUserName());
		if (temp != null) {
			return new Result<>(Result.ResultStatus.FAILED.code, "用户名重复");
		}

		user.setCreateDate(LocalDateTime.now());
		user.setPassword(MD5Util.getMD5(user.getPassword()));
		userDao.insertUser(user);
		if (user.getRoles() != null && user.getRoles().size() > 0) {
			user.getRoles().stream().forEach(item -> {
				userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
			});
		}

		return new Result<>(Result.ResultStatus.SUCCESS.code, "Insert success.", user);
	}

	@Override
	@Transactional
	@GlobalTransactional
	public Result<User> updateUser(User user) {
		User temp = userDao.getUserByUserName(user.getUserName());
		if (temp != null && temp.getId() != user.getId()) {
			return new Result<>(Result.ResultStatus.FAILED.code, "用户名重复");
		}

		// 测试分布式事务，调用 updateCity 接口
		City city = new City();
		city.setCityId(1890);
		city.setCityName("shanghai" + user.getId());
		city.setLocalCityName("上海" + user.getId());
		city.setCountryId(522);
		city.setDateCreated(LocalDateTime.now());
		city.setDateModified(LocalDateTime.now());
		testFeignClient.updateCity(city);

		// 模拟抛出运行时异常
		if (user.getId() > 1) {
			int i = 1 / 0;
		}

		userDao.updateUser(user);
		userRoleDao.deleteUserRolesByUserId(user.getId());
		if (user.getRoles() != null && user.getRoles().size() > 0) {
			user.getRoles().stream().forEach(item -> {
				userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
			});
		}

		return new Result<>(Result.ResultStatus.SUCCESS.code, "Update success.", user);
	}

	@Override
	@Transactional
	public Result<Object> deleteUserById(int id) {
		userDao.deleteUserById(id);
		return new Result<>(Result.ResultStatus.SUCCESS.code, "Delete success.");
	}

	@Override
	@SentinelResource(value = "getUserById",
			blockHandler = "getUserByIdBlockHandler",
			fallback = "getUserByIdFallbackHandler")
	public User getUserById(int id) {
		if (id <= 0) {
			throw new RuntimeException("vfvvdsvdsvfd");
		}
		return userDao.getUserById(id);
	}

	// 捕获限流、降级等异常处理方盒，和控制面板的配置对应
	public User getUserByIdBlockHandler(int id, BlockException blockException) {
		if (blockException instanceof FlowException) {
			System.out.println("您被限流了。");
		} else if (blockException instanceof DegradeException) {
			System.out.println("您被降级了");
		}

		return new User();
	}

	// 捕获非限流、降级异常的处理逻辑
	public User getUserByIdFallbackHandler(int id) {
		System.out.println("捕获非限流、降级异常，进行熔断处理。");
		return new User();
	}

	@Override
	public User getUserByUserName(String userName) {
		return userDao.getUserByUserName(userName);
	}

	@Override
	public PageInfo<User> getUsersBySearch(Search search) {
		search.init();
		PageHelper.startPage(search.getCurrentPage(), search.getPageSize());
		return new PageInfo<>(Optional
				.ofNullable(userDao.getUsersBySearch(search))
				.orElse(Collections.emptyList()));
	}

	@Override
	public void logout() {
	}

	@Override
	@SentinelResource(value = "getUserVoByUserIdAndCityId", blockHandler = "blockHandler", fallback = "fallbackHandler")
	public UserVo getUserVoByUserIdAndCityId(int userId, int cityId) {
		if (userId < 0 ) {
			throw new RuntimeException("cdsacadscdascsad");
		}
		UserVo userVo = new UserVo();
		User user = userDao.getUserById(userId);
		BeanUtils.copyProperties(user, userVo);
		City city = testFeignClient.getCityByCityId(cityId);
		userVo.setCity(city);

		return userVo;
	}

	/**
	 * 流控或降级异常处理逻辑
	 */
	public UserVo blockHandler(int userId, int cityId, BlockException exception) {
		if (exception instanceof FlowException) {
			System.out.println("您被限流了.");
		} else if (exception instanceof DegradeException) {
			System.out.println("您被降级了.");
		} else {
			System.out.println("City 接口不可用.");
		}

		return new UserVo();
	}

	/**
	 * 非流控或降级异常处理逻辑
	 */
	public UserVo fallbackHandler(int userId, int cityId) {
		System.out.println("发生了非流控、降级异常，被熔断了.");
		return new UserVo();
	}
}
